﻿using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Data.AggregateRoots.Identity;
using Microsoft.AspNet.Identity;
using Microsoft.Practices.Unity;

namespace Web.Identity
{
    public class AppUserStore : IUserLockoutStore<IdentityUser, Guid>,
     IUserPasswordStore<IdentityUser, Guid>,
     IUserTwoFactorStore<IdentityUser, Guid>,
     IUserEmailStore<IdentityUser, Guid>,
     IUserLoginStore<IdentityUser, Guid>
    {
        [Dependency]
        internal IIdentityUserQueryEntry UserQueryEntry { get; set; }

        public async Task CreateAsync(IdentityUser user)
        {
            var command = new UserAddCommand
            {
                IdentityUser = user
            };
            await AppConfiguration.CommandBus.SendAsync<UserAddCommand, IdentityUser>(command);
        }

        public async Task DeleteAsync(IdentityUser user)
        {
            var command = new UserDeleteCommand
            {
                UserId = user.Id
            };
            await AppConfiguration.CommandBus.SendAsync(command);
        }

        public async Task<IdentityUser> FindByIdAsync(Guid userId)
        {
            return await UserQueryEntry.TryGetAsync(userId);
        }

        public async Task<IdentityUser> FindByNameAsync(string userName)
        {
            return await UserQueryEntry.TryGetByNameAsync(userName);
        }

        public async Task UpdateAsync(IdentityUser user)
        {
            await Task.FromResult(0);
        }

        public void Dispose()
        {
            //do nothing
        }

        public async Task<DateTimeOffset> GetLockoutEndDateAsync(IdentityUser user)
        {
            return await Task.FromResult(new DateTimeOffset(DateTime.Now));
        }

        public async Task SetLockoutEndDateAsync(IdentityUser user, DateTimeOffset lockoutEnd)
        {
            await Task.FromResult(0);
        }

        public Task<int> IncrementAccessFailedCountAsync(IdentityUser user)
        {
            throw new NotImplementedException();
        }

        public async Task ResetAccessFailedCountAsync(IdentityUser user)
        {
            await Task.FromResult(0);
        }

        public async Task<int> GetAccessFailedCountAsync(IdentityUser user)
        {
            return await Task.FromResult(0);
        }

        public Task<bool> GetLockoutEnabledAsync(IdentityUser user)
        {
            return Task.FromResult(false);
        }

        public Task SetLockoutEnabledAsync(IdentityUser user, bool enabled)
        {
            return Task.FromResult(0);
        }

        public async Task SetPasswordHashAsync(IdentityUser user, string passwordHash)
        {
            var command = new PasswordHashUpdateCommand
            {
                UserId = user.Id,
                PasswordHash = passwordHash
            };
            await AppConfiguration.CommandBus.SendAsync(command);
        }

        public async Task<string> GetPasswordHashAsync(IdentityUser user)
        {
            var result = await UserQueryEntry.TryGetAsync(user.Id);
            return result.PasswordHash;
        }

        public async Task<bool> HasPasswordAsync(IdentityUser user)
        {
            var result = await UserQueryEntry.TryGetAsync(user.Id);
            return result.PasswordHash.IsNullOrEmpty();
        }

        public Task SetTwoFactorEnabledAsync(IdentityUser user, bool enabled)
        {
            //throw new NotSupportedException();
            return Task.FromResult(0);
        }

        public Task<bool> GetTwoFactorEnabledAsync(IdentityUser user)
        {
            //throw new NotSupportedException();
            return Task.FromResult(false);
        }

        public Task SetEmailAsync(IdentityUser user, string email)
        {
            throw new NotSupportedException();
        }

        public Task<string> GetEmailAsync(IdentityUser user)
        {
            throw new NotSupportedException();
        }

        public Task<bool> GetEmailConfirmedAsync(IdentityUser user)
        {
            throw new NotSupportedException();
        }

        public Task SetEmailConfirmedAsync(IdentityUser user, bool confirmed)
        {
            throw new NotSupportedException();
        }

        public Task<IdentityUser> FindByEmailAsync(string email)
        {
            throw new NotSupportedException();
        }

        public async Task AddLoginAsync(IdentityUser user, UserLoginInfo login)
        {
            var command = new LoginInfoAddCommand
            {
                User = user,
                LoginInfo = login
            };
            await AppConfiguration.CommandBus.SendAsync(command);
        }

        public async Task RemoveLoginAsync(IdentityUser user, UserLoginInfo login)
        {
            var command = new LoginInfoDeleteCommand
            {
                User = user,
                LoginInfo = login
            };
            await AppConfiguration.CommandBus.SendAsync(command);
        }

        public async Task<IList<UserLoginInfo>> GetLoginsAsync(IdentityUser user)
        {
            var result = await UserQueryEntry.TryGetAsync(user.Id);
            return result.LoginInfos.Select(i => new UserLoginInfo(i.ProviderKey, i.LoginProvider)).ToList();
        }

        public async Task<IdentityUser> FindAsync(UserLoginInfo login)
        {
            return await UserQueryEntry.TryGetByLoginInfoAsync(login.LoginProvider, login.ProviderKey);
        }
    }
}